home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / gfx / x11 / x3270_3_2_16.lha / amiga_src / sf.c < prev    next >
C/C++ Source or Header  |  2008-12-15  |  18KB  |  765 lines

  1. /*
  2.  * Copyright 1994, 1995, 1996, 1999, 2000 by Paul Mattes.
  3.  *  Permission to use, copy, modify, and distribute this software and its
  4.  *  documentation for any purpose and without fee is hereby granted,
  5.  *  provided that the above copyright notice appear in all copies and that
  6.  *  both that copyright notice and this permission notice appear in
  7.  *  supporting documentation.
  8.  */
  9.  
  10. /*
  11.  *    sf.c
  12.  *        This module handles 3270 structured fields.
  13.  *
  14.  */
  15.  
  16. #include "globals.h"
  17. #include <errno.h>
  18. #include "3270ds.h"
  19. #include "appres.h"
  20. #include "screen.h"
  21. #include "cg.h"
  22. #include "ctlr.h"
  23. #include "resources.h"
  24.  
  25. #include "ctlrc.h"
  26. #if defined(X3270_FT) /*[*/
  27. #include "ft_dftc.h"
  28. #endif /*]*/
  29. #include "kybdc.h"
  30. #include "screenc.h"
  31. #include "sfc.h"
  32. #include "telnetc.h"
  33. #include "trace_dsc.h"
  34. #include "utilc.h"
  35.  
  36. /* Externals: ctlr.c */
  37. extern Boolean  screen_alt;
  38. extern unsigned char reply_mode;
  39. extern int      crm_nattr;
  40. extern unsigned char crm_attr[];
  41.  
  42. /* Statics */
  43. static Boolean  qr_in_progress = False;
  44. static enum pds sf_read_part(unsigned char buf[], unsigned buflen);
  45. static enum pds sf_erase_reset(unsigned char buf[], int buflen);
  46. static enum pds sf_set_reply_mode(unsigned char buf[], int buflen);
  47. static enum pds sf_create_partition(unsigned char buf[], int buflen);
  48. static enum pds sf_outbound_ds(unsigned char buf[], int buflen);
  49. static void query_reply_start(void);
  50. static void do_query_reply(unsigned char code);
  51. static void query_reply_end(void);
  52.  
  53. static unsigned char supported_replies[] = {
  54.     QR_SUMMARY,        /* 0x80 */
  55.     QR_USABLE_AREA,        /* 0x81 */
  56.     QR_ALPHA_PART,        /* 0x84 */
  57.     QR_CHARSETS,        /* 0x85 */
  58.     QR_COLOR,        /* 0x86 */
  59.     QR_HIGHLIGHTING,    /* 0x87 */
  60.     QR_REPLY_MODES,        /* 0x88 */
  61.     QR_IMP_PART,        /* 0xa6 */
  62. #if defined(X3270_FT) /*[*/
  63.     QR_DDM,            /* 0x95 */
  64. #endif /*]*/
  65. };
  66. #define NSR    (sizeof(supported_replies)/sizeof(unsigned char))
  67.  
  68.  
  69.  
  70. /*
  71.  * Process a 3270 Write Structured Field command
  72.  */
  73. enum pds
  74. write_structured_field(unsigned char buf[], int buflen)
  75. {
  76.     unsigned short fieldlen;
  77.     unsigned char *cp = buf;
  78.     Boolean first = True;
  79.     enum pds rv = PDS_OKAY_NO_OUTPUT;
  80.     enum pds rv_this = PDS_OKAY_NO_OUTPUT;
  81.     Boolean bad_cmd = False;
  82.  
  83.     /* Skip the WSF command itself. */
  84.     cp++;
  85.     buflen--;
  86.  
  87.     /* Interpret fields. */
  88.     while (buflen > 0) {
  89.  
  90.         if (first)
  91.             trace_ds(" ");
  92.         else
  93.             trace_ds("< WriteStructuredField ");
  94.         first = False;
  95.  
  96.         /* Pick out the field length. */
  97.         if (buflen < 2) {
  98.             trace_ds("error: single byte at end of message\n");
  99.             return rv ? rv : PDS_BAD_CMD;
  100.         }
  101.         fieldlen = (cp[0] << 8) + cp[1];
  102.         if (fieldlen == 0)
  103.             fieldlen = buflen;
  104.         if (fieldlen < 3) {
  105.             trace_ds("error: field length %d too small\n",
  106.                 fieldlen);
  107.             return rv ? rv : PDS_BAD_CMD;
  108.         }
  109.         if ((int)fieldlen > buflen) {
  110.             trace_ds("error: field length %d exceeds remaining "
  111.                 "message length %d\n",
  112.                 fieldlen, buflen);
  113.             return rv ? rv : PDS_BAD_CMD;
  114.         }
  115.  
  116.         /* Dispatch on the ID. */
  117.         switch (cp[2]) {
  118.             case SF_READ_PART:
  119.             trace_ds("ReadPartition");
  120.             rv_this = sf_read_part(cp, (int)fieldlen);
  121.             break;
  122.             case SF_ERASE_RESET:
  123.             trace_ds("EraseReset");
  124.             rv_this = sf_erase_reset(cp, (int)fieldlen);
  125.             break;
  126.             case SF_SET_REPLY_MODE:
  127.             trace_ds("SetReplyMode");
  128.             rv_this = sf_set_reply_mode(cp, (int)fieldlen);
  129.             break;
  130.             case SF_CREATE_PART:
  131.             trace_ds("CreatePartition");
  132.             rv_this = sf_create_partition(cp, (int)fieldlen);
  133.             break;
  134.             case SF_OUTBOUND_DS:
  135.             trace_ds("OutboundDS");
  136.             rv_this = sf_outbound_ds(cp, (int)fieldlen);
  137.             break;
  138. #if defined(X3270_FT) /*[*/
  139.             case SF_TRANSFER_DATA:   /* File transfer data         */
  140.             trace_ds("FileTransferData");
  141.             ft_dft_data(cp, (int)fieldlen);
  142.             break;
  143. #endif /*]*/
  144.             default:
  145.             trace_ds("unsupported ID 0x%02x\n", cp[2]);
  146.             rv_this = PDS_BAD_CMD;
  147.             break;
  148.         }
  149.  
  150.         /*
  151.          * Accumulate errors or output flags.
  152.          * One real ugliness here is that if we have already
  153.          * generated some output, then we have already positively
  154.          * acknowledged the request, so if we fail here, we have no
  155.          * way to return the error indication.
  156.          */
  157.         if (rv_this < 0)
  158.             bad_cmd = True;
  159.         else
  160.             rv |= rv_this;
  161.  
  162.         /* Skip to the next field. */
  163.         cp += fieldlen;
  164.         buflen -= fieldlen;
  165.     }
  166.     if (first)
  167.         trace_ds(" (null)\n");
  168.  
  169.     if (bad_cmd && !rv)
  170.         return PDS_BAD_CMD;
  171.     else
  172.         return rv;
  173. }
  174.  
  175. static enum pds
  176. sf_read_part(unsigned char buf[], unsigned buflen)
  177. {
  178.     unsigned char partition;
  179.     unsigned i;
  180.     int any = 0;
  181.     const char *comma = "";
  182.  
  183.     if (buflen < 5) {
  184.         trace_ds(" error: field length %d too small\n", buflen);
  185.         return PDS_BAD_CMD;
  186.     }
  187.  
  188.     partition = buf[3];
  189.     trace_ds("(0x%02x)", partition);
  190.  
  191.     switch (buf[4]) {
  192.         case SF_RP_QUERY:
  193.         trace_ds(" Query");
  194.         if (partition != 0xff) {
  195.             trace_ds(" error: illegal partition\n");
  196.             return PDS_BAD_CMD;
  197.         }
  198.         trace_ds("\n");
  199.         query_reply_start();
  200.         for (i = 0; i < NSR; i++)
  201.               do_query_reply(supported_replies[i]);
  202.          query_reply_end();
  203.         break;
  204.         case SF_RP_QLIST:
  205.         trace_ds(" QueryList ");
  206.         if (partition != 0xff) {
  207.             trace_ds("error: illegal partition\n");
  208.             return PDS_BAD_CMD;
  209.         }
  210.         if (buflen < 6) {
  211.             trace_ds("error: missing request type\n");
  212.             return PDS_BAD_CMD;
  213.         }
  214.         query_reply_start();
  215.         switch (buf[5]) {
  216.             case SF_RPQ_LIST:
  217.             trace_ds("List(");
  218.             if (buflen < 7) {
  219.                 trace_ds(")\n");
  220.                 do_query_reply(QR_NULL);
  221.             } else {
  222.                 for (i = 6; i < buflen; i++) {
  223.                     trace_ds("%s%s", comma,
  224.                         see_qcode(buf[i]));
  225.                     comma = ",";
  226.                 }
  227.                 trace_ds(")\n");
  228.                 for (i = 0; i < NSR; i++) {
  229.                     if (memchr((char *)&buf[6],
  230.                            (char)supported_replies[i],
  231.                            buflen-6)) {
  232.                         do_query_reply(supported_replies[i]);
  233.                         any++;
  234.                     }
  235.                 }
  236.                 if (!any) {
  237.                     do_query_reply(QR_NULL);
  238.                 }
  239.             }
  240.             break;
  241.             case SF_RPQ_EQUIV:
  242.             trace_ds("Equivlent+List(");
  243.             for (i = 6; i < buflen; i++) {
  244.                 trace_ds("%s%s", comma, see_qcode(buf[i]));
  245.                 comma = ",";
  246.             }
  247.             trace_ds(")\n");
  248.             for (i = 0; i < NSR; i++)
  249.                 do_query_reply(supported_replies[i]);
  250.             break;
  251.             case SF_RPQ_ALL:
  252.             trace_ds("All\n");
  253.             for (i = 0; i < NSR; i++)
  254.                 do_query_reply(supported_replies[i]);
  255.             break;
  256.             default:
  257.             trace_ds("unknown request type 0x%02x\n", buf[5]);
  258.             return PDS_BAD_CMD;
  259.         }
  260.         query_reply_end();
  261.         break;
  262.         case SNA_CMD_RMA:
  263.         trace_ds(" ReadModifiedAll");
  264.         if (partition != 0x00) {
  265.             trace_ds(" error: illegal partition\n");
  266.             return PDS_BAD_CMD;
  267.         }
  268.         trace_ds("\n");
  269.         ctlr_read_modified(AID_QREPLY, True);
  270.         break;
  271.         case SNA_CMD_RB:
  272.         trace_ds(" ReadBuffer");
  273.         if (partition != 0x00) {
  274.             trace_ds(" error: illegal partition\n");
  275.             return PDS_BAD_CMD;
  276.         }
  277.         trace_ds("\n");
  278.         ctlr_read_buffer(AID_QREPLY);
  279.         break;
  280.         case SNA_CMD_RM:
  281.         trace_ds(" ReadModified");
  282.         if (partition != 0x00) {
  283.             trace_ds(" error: illegal partition\n");
  284.             return PDS_BAD_CMD;
  285.         }
  286.         trace_ds("\n");
  287.         ctlr_read_modified(AID_QREPLY, False);
  288.         break;
  289.         default:
  290.         trace_ds(" unknown type 0x%02x\n", buf[4]);
  291.         return PDS_BAD_CMD;
  292.     }
  293.     return PDS_OKAY_OUTPUT;
  294. }
  295.  
  296. static enum pds
  297. sf_erase_reset(unsigned char buf[], int buflen)
  298. {
  299.     if (buflen != 4) {
  300.         trace_ds(" error: wrong field length %d\n", buflen);
  301.         return PDS_BAD_CMD;
  302.     }
  303.  
  304.     switch (buf[3]) {
  305.         case SF_ER_DEFAULT:
  306.         trace_ds(" Default\n");
  307.         ctlr_erase(False);
  308.         break;
  309.         case SF_ER_ALT:
  310.         trace_ds(" Alternate\n");
  311.         ctlr_erase(True);
  312.         break;
  313.         default:
  314.         trace_ds(" unknown type 0x%02x\n", buf[3]);
  315.         return PDS_BAD_CMD;
  316.     }
  317.     return PDS_OKAY_NO_OUTPUT;
  318. }
  319.  
  320. static enum pds
  321. sf_set_reply_mode(unsigned char buf[], int buflen)
  322. {
  323.     unsigned char partition;
  324.     int i;
  325.     const char *comma = "(";
  326.  
  327.     if (buflen < 5) {
  328.         trace_ds(" error: wrong field length %d\n", buflen);
  329.         return PDS_BAD_CMD;
  330.     }
  331.  
  332.     partition = buf[3];
  333.     trace_ds("(0x%02x)", partition);
  334.     if (partition != 0x00) {
  335.         trace_ds(" error: illegal partition\n");
  336.         return PDS_BAD_CMD;
  337.     }
  338.  
  339.     switch (buf[4]) {
  340.         case SF_SRM_FIELD:
  341.         trace_ds(" Field\n");
  342.         break;
  343.         case SF_SRM_XFIELD:
  344.         trace_ds(" ExtendedField\n");
  345.         break;
  346.         case SF_SRM_CHAR:
  347.         trace_ds(" Character");
  348.         break;
  349.         default:
  350.         trace_ds(" unknown mode 0x%02x\n", buf[4]);
  351.         return PDS_BAD_CMD;
  352.     }
  353.     reply_mode = buf[4];
  354.     if (buf[4] == SF_SRM_CHAR) {
  355.         crm_nattr = buflen - 5;
  356.         for (i = 5; i < buflen; i++) {
  357.             crm_attr[i - 5] = buf[i];
  358.             trace_ds("%s%s", comma, see_efa_only(buf[i]));
  359.             comma = ",";
  360.         }
  361.         trace_ds("%s\n", crm_nattr ? ")" : "");
  362.     }
  363.     return PDS_OKAY_NO_OUTPUT;
  364. }
  365.  
  366. static enum pds
  367. sf_create_partition(unsigned char buf[], int buflen)
  368. {
  369.     unsigned char pid;
  370.     unsigned char uom;        /* unit of measure */
  371.     unsigned char am;        /* addressing mode */
  372.     unsigned char flags;        /* flags */
  373.     unsigned short h;        /* height of presentation space */
  374.     unsigned short w;        /* width of presentation space */
  375.     unsigned short rv;        /* viewport origin row */
  376.     unsigned short cv;        /* viewport origin column */
  377.     unsigned short hv;        /* viewport height */
  378.     unsigned short wv;        /* viewport width */
  379.     unsigned short rw;        /* window origin row */
  380.     unsigned short cw;        /* window origin column */
  381.     unsigned short rs;        /* scroll rows */
  382.     /* hole */
  383.     unsigned short pw;        /* character cell point width */
  384.     unsigned short ph;        /* character cell point height */
  385.  
  386.     static const char *bit4[16] = {
  387.         "0000", "0001", "0010", "0011",
  388.         "0100", "0101", "0110", "0111",
  389.         "1000", "1001", "1010", "1011",
  390.         "1100", "1101", "1110", "1111"
  391.     };
  392.  
  393.     if (buflen > 3) {
  394.         trace_ds("(");
  395.  
  396.         /* Partition. */
  397.         pid = buf[3];
  398.         trace_ds("pid=0x%02x", pid);
  399.         if (pid != 0x00) {
  400.             trace_ds(") error: illegal partition\n");
  401.             return PDS_BAD_CMD;
  402.         }
  403.     } else
  404.         pid = 0x00;
  405.  
  406.     if (buflen > 4) {
  407.         uom = (buf[4] & 0xf0) >> 4;
  408.         trace_ds(",uom=B'%s'", bit4[uom]);
  409.         if (uom != 0x0 && uom != 0x02) {
  410.             trace_ds(") error: illegal units\n");
  411.             return PDS_BAD_CMD;
  412.         }
  413.         am = buf[4] & 0x0f;
  414.         trace_ds(",am=B'%s'", bit4[am]);
  415.         if (am > 0x2) {
  416.             trace_ds(") error: illegal a-mode\n");
  417.             return PDS_BAD_CMD;
  418.         }
  419.     } else {
  420.         uom = 0;
  421.         am = 0;
  422.     }
  423.  
  424.     if (buflen > 5) {
  425.         flags = buf[5];
  426.         trace_ds(",flags=0x%02x", flags);
  427.     } else
  428.         flags = 0;
  429.  
  430.     if (buflen > 7) {
  431.         GET16(h, &buf[6]);
  432.         trace_ds(",h=%d", h);
  433.     } else
  434.         h = maxROWS;
  435.  
  436.     if (buflen > 9) {
  437.         GET16(w, &buf[8]);
  438.         trace_ds(",w=%d", w);
  439.     } else
  440.         w = maxCOLS;
  441.  
  442.     if (buflen > 11) {
  443.         GET16(rv, &buf[10]);
  444.         trace_ds(",rv=%d", rv);
  445.     } else
  446.         rv = 0;
  447.  
  448.     if (buflen > 13) {
  449.         GET16(cv, &buf[12]);
  450.         trace_ds(",cv=%d", cv);
  451.     } else
  452.         cv = 0;
  453.  
  454.     if (buflen > 15) {
  455.         GET16(hv, &buf[14]);
  456.         trace_ds(",hv=%d", hv);
  457.     } else
  458.         hv = (h > maxROWS)? maxROWS: h;
  459.  
  460.     if (buflen > 17) {
  461.         GET16(wv, &buf[16]);
  462.         trace_ds(",wv=%d", wv);
  463.     } else
  464.         wv = (w > maxCOLS)? maxCOLS: w;
  465.  
  466.     if (buflen > 19) {
  467.         GET16(rw, &buf[18]);
  468.         trace_ds(",rw=%d", rw);
  469.     } else
  470.         rw = 0;
  471.  
  472.     if (buflen > 21) {
  473.         GET16(cw, &buf[20]);
  474.         trace_ds(",cw=%d", cw);
  475.     } else
  476.         cw = 0;
  477.  
  478.     if (buflen > 23) {
  479.         GET16(rs, &buf[22]);
  480.         trace_ds(",rs=%d", rs);
  481.     } else
  482.         rs = (h > hv)? 1: 0;
  483.  
  484.     if (buflen > 27) {
  485.         GET16(pw, &buf[26]);
  486.         trace_ds(",pw=%d", pw);
  487.     } else
  488.         pw = *char_width;
  489.  
  490.     if (buflen > 29) {
  491.         GET16(ph, &buf[28]);
  492.         trace_ds(",ph=%d", ph);
  493.     } else
  494.         ph = *char_height;
  495.     trace_ds(")\n");
  496.  
  497.     cursor_move(0);
  498.     buffer_addr = 0;
  499.  
  500.     return PDS_OKAY_NO_OUTPUT;
  501. }
  502.  
  503. static enum pds
  504. sf_outbound_ds(unsigned char buf[], int buflen)
  505. {
  506.     if (buflen < 5) {
  507.         trace_ds(" error: field length %d too short\n", buflen);
  508.         return PDS_BAD_CMD;
  509.     }
  510.  
  511.     trace_ds("(0x%02x)", buf[3]);
  512.     if (buf[3] != 0x00) {
  513.         trace_ds(" error: illegal partition 0x%0x\n", buf[3]);
  514.         return PDS_BAD_CMD;
  515.     }
  516.  
  517.     switch (buf[4]) {
  518.         case SNA_CMD_W:
  519.         trace_ds(" Write");
  520.         if (buflen > 5)
  521.             ctlr_write(&buf[4], buflen-4, False);
  522.         else
  523.             trace_ds("\n");
  524.         break;
  525.         case SNA_CMD_EW:
  526.         trace_ds(" EraseWrite");
  527.         ctlr_erase(screen_alt);
  528.         if (buflen > 5)
  529.             ctlr_write(&buf[4], buflen-4, True);
  530.         else
  531.             trace_ds("\n");
  532.         break;
  533.         case SNA_CMD_EWA:
  534.         trace_ds(" EraseWriteAlternate");
  535.         ctlr_erase(screen_alt);
  536.         if (buflen > 5)
  537.             ctlr_write(&buf[4], buflen-4, True);
  538.         else
  539.             trace_ds("\n");
  540.         break;
  541.         case SNA_CMD_EAU:
  542.         trace_ds(" EraseAllUnprotected\n");
  543.         ctlr_erase_all_unprotected();
  544.         break;
  545.         default:
  546.         trace_ds(" unknown type 0x%02x\n", buf[4]);
  547.         return PDS_BAD_CMD;
  548.     }
  549.     return PDS_OKAY_NO_OUTPUT;
  550. }
  551.  
  552. static void
  553. query_reply_start(void)
  554. {
  555.     obptr = obuf;
  556.     space3270out(1);
  557.     *obptr++ = AID_SF;
  558.     qr_in_progress = True;
  559. }
  560.  
  561. static void
  562. do_query_reply(unsigned char code)
  563. {
  564.     int len;
  565.     unsigned i;
  566.     const char *comma = "";
  567.     int obptr0 = obptr - obuf;
  568.     unsigned char *obptr_len;
  569.     unsigned short num, denom;
  570.     char *cp_name;
  571.     char *cp_value;
  572.     unsigned long cp;
  573.     char *ptr;
  574.  
  575.     if (qr_in_progress) {
  576.         trace_ds("> StructuredField\n");
  577.         qr_in_progress = False;
  578.     }
  579.  
  580.     space3270out(4);
  581.     obptr += 2;    /* skip length for now */
  582.     *obptr++ = SFID_QREPLY;
  583.     *obptr++ = code;
  584.     switch (code) {
  585.  
  586.         case QR_CHARSETS:
  587.         trace_ds("> QueryReply(CharacterSets)\n");
  588.         space3270out(23);
  589.         *obptr++ = 0x82;    /* flags: GE, CGCSGID present */
  590.         *obptr++ = 0x00;    /* more flags */
  591.         *obptr++ = *char_width;    /* SDW */
  592.         *obptr++ = *char_height;/* SDH */
  593.         *obptr++ = 0x00;    /* Load PS format types */
  594.         *obptr++ = 0x00;
  595.         *obptr++ = 0x00;
  596.         *obptr++ = 0x00;
  597.         *obptr++ = 0x07;    /* DL */
  598.         *obptr++ = 0x00;    /* SET 0: */
  599.         *obptr++ = 0x10;    /*  FLAGS: non-loadable, single-plane,
  600.                          single-byte, no compare */
  601.         *obptr++ = 0x00;    /*  LCID */
  602.         *obptr++ = 0x02;    /*  CGCSGID: English (U.S.) */
  603.         *obptr++ = 0xb9;
  604.         /* Get the codepage resource. */
  605.         cp_name = xs_buffer("%s.%s", ResCodepage, appres.charset);
  606.         cp_value = get_resource(cp_name);
  607.         if (cp_value != CN &&
  608.             (cp = strtoul(cp_value, &ptr, 0)) &&
  609.             ptr != cp_value &&
  610.             *ptr == '\0' &&
  611.             !(cp & ~0xffffL)) {
  612.             /* Reasonable non-default value defined. */
  613.             SET16(obptr, cp);
  614.         } else {
  615.             /* Default to codepage 37. */
  616.             *obptr++ = 0x00;
  617.             *obptr++ = 0x25;
  618.         }
  619.         Free(cp_name);
  620.         if (!*standard_font) {
  621.             /* special 3270 font, includes APL */
  622.             *obptr++ = 0x01;/* SET 1: */
  623.             *obptr++ = 0x10;/*  FLAGS: non-loadable, single-plane,
  624.                          single-byte, no compare */
  625.             *obptr++ = 0xf1;/*  LCID */
  626.             *obptr++ = 0x03;/*  CGCSGID: 3179-style APL2 */
  627.             *obptr++ = 0xc3;
  628.             *obptr++ = 0x01;
  629.             *obptr++ = 0x36;
  630.         }
  631.         break;
  632.  
  633.         case QR_IMP_PART:
  634.         trace_ds("> QueryReply(ImplicitPartition)\n");
  635.         space3270out(13);
  636.         *obptr++ = 0x0;        /* reserved */
  637.         *obptr++ = 0x0;
  638.         *obptr++ = 0x0b;    /* length of display size */
  639.         *obptr++ = 0x01;    /* "implicit partition size" */
  640.         *obptr++ = 0x00;    /* reserved */
  641.         SET16(obptr, 80);    /* implicit partition width */
  642.         SET16(obptr, 24);    /* implicit partition height */
  643.         SET16(obptr, maxCOLS);    /* alternate height */
  644.         SET16(obptr, maxROWS);    /* alternate width */
  645.         break;
  646.  
  647.         case QR_NULL:
  648.         trace_ds("> QueryReply(Null)\n");
  649.         break;
  650.  
  651.         case QR_SUMMARY:
  652.         trace_ds("> QueryReply(Summary(");
  653.         space3270out(NSR);
  654.         for (i = 0; i < NSR; i++) {
  655.             trace_ds("%s%s", comma,
  656.                 see_qcode(supported_replies[i]));
  657.             comma = ",";
  658.             *obptr++ = supported_replies[i];
  659.         }
  660.         trace_ds("))\n");
  661.         break;
  662.  
  663.         case QR_USABLE_AREA:
  664.         trace_ds("> QueryReply(UsableArea)\n");
  665.         space3270out(19);
  666.         *obptr++ = 0x01;    /* 12/14-bit addressing */
  667.         *obptr++ = 0x00;    /* no special character features */
  668.         SET16(obptr, maxCOLS);    /* usable width */
  669.         SET16(obptr, maxROWS);    /* usable height */
  670.         *obptr++ = 0x01;    /* units (mm) */
  671.         num = display_widthMM();
  672.         denom = display_width();
  673.         while (!(num %2) && !(denom % 2)) {
  674.             num /= 2;
  675.             denom /= 2;
  676.         }
  677.         SET16(obptr, (int)num);    /* Xr numerator */
  678.         SET16(obptr, (int)denom); /* Xr denominator */
  679.         num = display_heightMM();
  680.         denom = display_height();
  681.         while (!(num %2) && !(denom % 2)) {
  682.             num /= 2;
  683.             denom /= 2;
  684.         }
  685.         SET16(obptr, (int)num);    /* Yr numerator */
  686.         SET16(obptr, (int)denom); /* Yr denominator */
  687.         *obptr++ = *char_width;    /* AW */
  688.         *obptr++ = *char_height;/* AH */
  689.         SET16(obptr, maxCOLS*maxROWS);    /* buffer, questionable */
  690.         break;
  691.  
  692.         case QR_COLOR:
  693.         trace_ds("> QueryReply(Color)\n");
  694.         space3270out(4 + 2*15);
  695.         *obptr++ = 0x00;    /* no options */
  696.         *obptr++ = 16;        /* report on 16 colors */
  697.         *obptr++ = 0x00;    /* default color: */
  698.         *obptr++ = 0xf0 + COLOR_GREEN;    /*  green */
  699.         for (i = 0xf1; i <= 0xff; i++) {
  700.             *obptr++ = i;
  701.             if (appres.m3279)
  702.                 *obptr++ = i;
  703.             else
  704.                 *obptr++ = 0x00;
  705.         }
  706.         break;
  707.  
  708.         case QR_HIGHLIGHTING:
  709.         trace_ds("> QueryReply(Highlighting)\n");
  710.         space3270out(11);
  711.         *obptr++ = 5;        /* report on 5 pairs */
  712.         *obptr++ = XAH_DEFAULT;    /* default: */
  713.         *obptr++ = XAH_NORMAL;    /*  normal */
  714.         *obptr++ = XAH_BLINK;    /* blink: */
  715.         *obptr++ = XAH_BLINK;    /*  blink */
  716.         *obptr++ = XAH_REVERSE;    /* reverse: */
  717.         *obptr++ = XAH_REVERSE;    /*  reverse */
  718.         *obptr++ = XAH_UNDERSCORE; /* underscore: */
  719.         *obptr++ = XAH_UNDERSCORE; /*  underscore */
  720.         *obptr++ = XAH_INTENSIFY; /* intensify: */
  721.         *obptr++ = XAH_INTENSIFY; /*  intensify */
  722.         break;
  723.  
  724.         case QR_REPLY_MODES:
  725.         trace_ds("> QueryReply(ReplyModes)\n");
  726.         space3270out(3);
  727.         *obptr++ = SF_SRM_FIELD;
  728.         *obptr++ = SF_SRM_XFIELD;
  729.         *obptr++ = SF_SRM_CHAR;
  730.         break;
  731.  
  732.         case QR_ALPHA_PART:
  733.         trace_ds("> QueryReply(AlphanumericPartitions)\n");
  734.         space3270out(4);
  735.         *obptr++ = 0;        /* 1 partition */
  736.         SET16(obptr, maxROWS*maxCOLS);    /* buffer space */
  737.         *obptr++ = 0;        /* no special features */
  738.         break;
  739.  
  740. #if defined(X3270_FT) /*[*/
  741.         case QR_DDM:
  742.         trace_ds("> QueryReply(DistributedDataManagement)\n");
  743.         space3270out(8);
  744.         SET16(obptr,0);        /* set reserved field to 0 */
  745.         SET16(obptr,2048);    /* set inbound length limit */
  746.         SET16(obptr,2048);    /* set outbound length limit */
  747.         SET16(obptr,0x0101);    /* NSS=01, DDMSS=01 */
  748.         break;
  749. #endif /*]*/
  750.  
  751.         default:
  752.         return;    /* internal error */
  753.     }
  754.     obptr_len = obuf + obptr0;
  755.     len = (obptr - obuf) - obptr0;
  756.     SET16(obptr_len, len);
  757. }
  758.  
  759. static void
  760. query_reply_end(void)
  761. {
  762.     net_output();
  763.     kybd_inhibit(True);
  764. }
  765.